﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using UtilZ.Dotnet.Ex.ZLog;

namespace UtilZ.Dotnet.Ex.Communication.Net.Ftp
{
    /// <summary>
    /// 认证用户名
    /// Authentication username.
    /// </summary>
    internal class FtpUSERCommand : FtpCommandAbs
    {
        /***********************************************************************************************************
        * [USER]（User Name，用户名称）
        * 
        * 说明：指定远程系统上的用户名称。和PASS命令一起使用来登录。
        * 用法：USER<User><CRLF>
        * 参数：UserName是FTP系统上已经注册的用户名称。
        * 例子：
        * SendData "USER johns" + “/r/n
        * 
        * 注释：在连接到一台FTP服务器的端口并接收到一个由代码220开头的行，表示服务器已经准备好用户向它发送USER和PASS命令以登录进此FTP服务器之后，紧跟着发送USER命令。
        * PASS命令应该紧跟着USER命令。
        * 如果在此FTP服务器上有帐号，就可以指定自己的用户名和密码。如果想匿名登录，可以指定用户名为“Anonymous”，而用自己的电子邮件地址当密码。
        * 在会话期间，可以随时发送USER和PASS命令，把控制权交给一个新用户。
        * 返回值如下（粗体表示成功）
        * 230  用户已经登录。
        * 331  用户名正常，需要密码。
        * 332  登录需要帐号。
        * 421  服务不可用，关闭控制连接
        * 
        * 如果某项服务获知自己即将关闭，会向所有命令做出这个应答
        * 500  语法错误，无法识别命令。这其中包括命令行过长之类的错误。
        * 501  参数或变元中有语法错误。
        * 530  无法登录。
        ************************************************************************************************************/


        public FtpUSERCommand()
            : base()
        {

        }

        protected override string[] GetNames()
        {
            return new string[] { FtpCommands.USER };
        }

        protected override IFtpResponse PrimitiveExcute(FtpSession session, string command, string commandLine)
        {
            //Request: USER anonymous
            //Response: 331 Anonymous access allowed, send identity (e-mail name) as password.
            //Response: 331 Anonymous access allowed, send identity (e-mail name) as password.

            try
            {
                if (session.SessionStatus == FtpSessionStatus.Success)
                {
                    //用户已经登录
                    return new FtpCodeResponse(FtpStatusCodes.Code230);
                }

                string userName = commandLine;
                if (string.IsNullOrWhiteSpace(userName))
                {
                    //账号为空,登录需要帐号
                    return new FtpCodeResponse(FtpStatusCodes.Code332);
                }

                FtpConfig config = session.FtpServer.Config;

                //先验证匿名用户
                if (config.AllowAnonymous &&
                    !string.IsNullOrWhiteSpace(config.Anonymous) &&
                    string.Equals(config.Anonymous, userName, StringComparison.OrdinalIgnoreCase))
                {
                    session.SessionStatus = FtpSessionStatus.AnonymousAccountValid;
                    session.FtpUser = config.AnonymousUserInfo;                    
                    return new FtpCodeResponse(FtpStatusCodes.Code331, $"{userName} access allowed, send identity (e-mail name) as password.");
                }

                //再验证指定用户
                List<FtpUserInfo> users = config.Users;
                if (users != null && users.Count > 0)
                {
                    var user = users.Find(t => { return string.Equals(t.UserName, userName, StringComparison.OrdinalIgnoreCase); });
                    if (user != null)
                    {
                        session.FtpUser = user;
                        session.SessionStatus = FtpSessionStatus.AccountValid;
                        return new FtpCodeResponse(FtpStatusCodes.Code331, $"{userName} access allowed, send identity (e-mail name) as password.");
                    }
                }

                //无效用户
                return new FtpCodeResponse(FtpStatusCodes.Code530, $"{userName} not access allowed.");
            }
            catch (Exception ex)
            {
                return new FtpCodeResponse(FtpStatusCodes.Code451, ex.Message);
            }
        }
    }

}
